package com.dhl.fin.api.service;

import com.dhl.fin.api.common.enums.CacheKeyEnum;
import com.dhl.fin.api.common.service.RedisService;
import com.dhl.fin.api.common.util.MapUtil;
import com.dhl.fin.api.common.util.WebUtil;
import com.dhl.fin.api.domain.*;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

/**
 * @author becui
 * @date 5/1/2020
 */
@Transactional(rollbackFor = Exception.class)
@Service
public class LoginServiceImpl {


    @Autowired
    private AccountServiceImpl accountService;
    @Autowired
    private RedisService redisService;


    public Map getLoginUserPermission() throws Exception {
        ExecutorService executorService = Executors.newFixedThreadPool(5);
        String uuid = WebUtil.getLoginUser().getUuid();
        Map<String, List<Dictionary>> dictionaries = redisService.getMap(CacheKeyEnum.DICTIONARIES_PER_APP);

        Account account = accountService.getLoginUser(uuid);
        List<Integer> count = new LinkedList<>();

        Map acctData = MapUtil.builder()
                .add("dictionaries", dictionaries)
                .add("loginUser", account)
                .build();
        executorService.execute(new projectsThread(acctData, count, uuid));
        executorService.execute(new manageProjectsThread(acctData, count, uuid));
        executorService.execute(new menuTreesThread(acctData, count, uuid));
        executorService.execute(new actionsThread(acctData, count, uuid));
        while (count.size() < 4) {
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
        executorService.shutdown();
        return acctData;
    }

    private class projectsThread implements Runnable {

        private String uuid;
        private Map acctData;
        private List<Integer> count;

        projectsThread(Map acctData, List<Integer> count, String uuid) {
            this.uuid = uuid;
            this.acctData = acctData;
            this.count = count;
        }

        @Override
        public void run() {
            try {
                List<Project> projects = accountService.getProjectsByUUID(uuid);
                acctData.put("projects", projects);
            } catch (Exception e) {
                e.printStackTrace();
            }

            this.count.add(1);
        }
    }

    private class manageProjectsThread implements Runnable {

        private String uuid;
        private Map acctData;
        private List<Integer> count;

        manageProjectsThread(Map acctData, List<Integer> count, String uuid) {
            this.uuid = uuid;
            this.acctData = acctData;
            this.count = count;
        }

        @Override
        public void run() {
            try {
                List<Project> manageProjects = accountService.getManageProjectsByUUID(uuid);
                acctData.put("manageProjects", manageProjects);
            } catch (Exception e) {
                e.printStackTrace();
            }
            this.count.add(1);
        }
    }

    private class menuTreesThread implements Runnable {

        private String uuid;
        private Map acctData;
        private List<Integer> count;

        menuTreesThread(Map acctData, List<Integer> count, String uuid) {
            this.uuid = uuid;
            this.acctData = acctData;
            this.count = count;
        }

        @Override
        public void run() {
            try {
                Map<String, List<Tree>> menuTrees = accountService.getMenuTreePerProject(uuid);
                acctData.put("menus", menuTrees);
            } catch (Exception e) {
                e.printStackTrace();
            }
            this.count.add(1);
        }
    }

    private class actionsThread implements Runnable {

        private String uuid;
        private Map acctData;
        private List<Integer> count;

        actionsThread(Map acctData, List<Integer> count, String uuid) {
            this.uuid = uuid;
            this.acctData = acctData;
            this.count = count;
        }

        @Override
        public void run() {
            try {
                Map<String, List<Action>> actions = accountService.getActionsPerProject(uuid);
                acctData.put("actions", actions);
            } catch (Exception e) {
                e.printStackTrace();
            }
            this.count.add(1);
        }
    }


}
